//! # Kubernetes 工具函数
//!
//! 提供与 Kubernetes 交互的各种工具函数和辅助类。

use std::collections::HashMap;
use kube::Api;
use k8s_openapi::api::core::v1::{Namespace, Pod};
use serde::{Deserialize, Serialize};
use tracing::{info, debug, warn};

use crate::client::KubernetesClient;
use crate::error::{K8sError, K8sResult};

/// Kubernetes 工具类
pub struct K8sUtils;

impl K8sUtils {
    /// 验证 Kubernetes 资源名称
    pub fn validate_resource_name(name: &str) -> K8sResult<()> {
        if name.is_empty() {
            return Err(K8sError::config_error("资源名称不能为空"));
        }

        if name.len() > 253 {
            return Err(K8sError::config_error("资源名称长度不能超过 253 个字符"));
        }

        // Kubernetes 资源名称必须符合 DNS-1123 规范
        let valid_chars = name.chars().all(|c| {
            c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-' || c == '.'
        });

        if !valid_chars {
            return Err(K8sError::config_error("资源名称只能包含小写字母、数字、'-' 和 '.'"));
        }

        if name.starts_with('-') || name.ends_with('-') {
            return Err(K8sError::config_error("资源名称不能以 '-' 开头或结尾"));
        }

        Ok(())
    }

    /// 验证 Kubernetes 标签
    pub fn validate_labels(labels: &HashMap<String, String>) -> K8sResult<()> {
        for (key, value) in labels {
            Self::validate_label_key(key)?;
            Self::validate_label_value(value)?;
        }
        Ok(())
    }

    /// 验证标签键
    pub fn validate_label_key(key: &str) -> K8sResult<()> {
        if key.is_empty() {
            return Err(K8sError::config_error("标签键不能为空"));
        }

        if key.len() > 63 {
            return Err(K8sError::config_error("标签键长度不能超过 63 个字符"));
        }

        // 检查是否包含前缀
        if let Some((prefix, name)) = key.rsplit_once('/') {
            if prefix.len() > 253 {
                return Err(K8sError::config_error("标签键前缀长度不能超过 253 个字符"));
            }
            Self::validate_label_name(name)?;
        } else {
            Self::validate_label_name(key)?;
        }

        Ok(())
    }

    /// 验证标签名称部分
    fn validate_label_name(name: &str) -> K8sResult<()> {
        if name.is_empty() {
            return Err(K8sError::config_error("标签名称不能为空"));
        }

        let valid_chars = name.chars().all(|c| {
            c.is_ascii_alphanumeric() || c == '-' || c == '_' || c == '.'
        });

        if !valid_chars {
            return Err(K8sError::config_error("标签名称只能包含字母、数字、'-'、'_' 和 '.'"));
        }

        if !name.chars().next().unwrap().is_ascii_alphanumeric() ||
           !name.chars().last().unwrap().is_ascii_alphanumeric() {
            return Err(K8sError::config_error("标签名称必须以字母或数字开头和结尾"));
        }

        Ok(())
    }

    /// 验证标签值
    pub fn validate_label_value(value: &str) -> K8sResult<()> {
        if value.len() > 63 {
            return Err(K8sError::config_error("标签值长度不能超过 63 个字符"));
        }

        if value.is_empty() {
            return Ok(()); // 空值是允许的
        }

        let valid_chars = value.chars().all(|c| {
            c.is_ascii_alphanumeric() || c == '-' || c == '_' || c == '.'
        });

        if !valid_chars {
            return Err(K8sError::config_error("标签值只能包含字母、数字、'-'、'_' 和 '.'"));
        }

        if !value.chars().next().unwrap().is_ascii_alphanumeric() ||
           !value.chars().last().unwrap().is_ascii_alphanumeric() {
            return Err(K8sError::config_error("标签值必须以字母或数字开头和结尾"));
        }

        Ok(())
    }

    /// 生成标准的 Kubernetes 标签
    pub fn generate_standard_labels(app_name: &str, version: &str, component: &str) -> HashMap<String, String> {
        let mut labels = HashMap::new();
        labels.insert("app.kubernetes.io/name".to_string(), app_name.to_string());
        labels.insert("app.kubernetes.io/version".to_string(), version.to_string());
        labels.insert("app.kubernetes.io/component".to_string(), component.to_string());
        labels.insert("app.kubernetes.io/managed-by".to_string(), "rustcloud".to_string());
        labels
    }

    /// 获取当前 Pod 信息
    pub fn get_current_pod_info() -> PodInfo {
        PodInfo {
            name: std::env::var("HOSTNAME").unwrap_or_else(|_| "unknown".to_string()),
            namespace: std::env::var("POD_NAMESPACE").unwrap_or_else(|_| "default".to_string()),
            ip: std::env::var("POD_IP").unwrap_or_else(|_| "127.0.0.1".to_string()),
            node_name: std::env::var("NODE_NAME").ok(),
            service_account: std::env::var("SERVICE_ACCOUNT_NAME").ok(),
        }
    }

    /// 构建资源 YAML
    pub fn build_resource_yaml<T: Serialize>(resource: &T) -> K8sResult<String> {
        serde_yaml::to_string(resource)
            .map_err(|e| K8sError::config_error(format!("YAML 序列化失败: {}", e)))
    }

    /// 解析资源 YAML
    pub fn parse_resource_yaml<T: for<'de> Deserialize<'de>>(yaml: &str) -> K8sResult<T> {
        serde_yaml::from_str(yaml)
            .map_err(|e| K8sError::config_error(format!("YAML 解析失败: {}", e)))
    }
}

/// Pod 信息
#[derive(Debug, Clone)]
pub struct PodInfo {
    /// Pod 名称
    pub name: String,
    /// 命名空间
    pub namespace: String,
    /// Pod IP
    pub ip: String,
    /// 节点名称
    pub node_name: Option<String>,
    /// 服务账户
    pub service_account: Option<String>,
}

/// 命名空间管理器
pub struct NamespaceManager {
    /// Kubernetes 客户端
    client: std::sync::Arc<KubernetesClient>,
}

impl NamespaceManager {
    /// 创建新的命名空间管理器
    pub fn new(client: std::sync::Arc<KubernetesClient>) -> Self {
        Self { client }
    }

    /// 获取所有命名空间
    pub async fn list_namespaces(&self) -> K8sResult<Vec<String>> {
        debug!("获取所有命名空间");

        let namespaces: Api<Namespace> = Api::all(self.client.client().clone());
        let namespace_list = namespaces.list(&Default::default()).await
            .map_err(|e| K8sError::service_discovery_error(format!("无法列出命名空间: {}", e)))?;

        let names: Vec<String> = namespace_list.items
            .iter()
            .filter_map(|ns| ns.metadata.name.clone())
            .collect();

        info!("发现 {} 个命名空间", names.len());
        Ok(names)
    }

    /// 检查命名空间是否存在
    pub async fn namespace_exists(&self, name: &str) -> K8sResult<bool> {
        let namespaces: Api<Namespace> = Api::all(self.client.client().clone());
        match namespaces.get(name).await {
            Ok(_) => Ok(true),
            Err(kube::Error::Api(error_response)) if error_response.code == 404 => Ok(false),
            Err(e) => Err(K8sError::from(e)),
        }
    }

    /// 创建命名空间
    pub async fn create_namespace(&self, name: &str, labels: Option<HashMap<String, String>>) -> K8sResult<()> {
        info!("创建命名空间: {}", name);

        K8sUtils::validate_resource_name(name)?;

        let namespaces: Api<Namespace> = Api::all(self.client.client().clone());
        
        let btreemap_labels = labels.map(|l| l.into_iter().collect());
        
        let namespace = Namespace {
            metadata: k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta {
                name: Some(name.to_string()),
                labels: btreemap_labels,
                ..Default::default()
            },
            ..Default::default()
        };

        namespaces.create(&Default::default(), &namespace).await
            .map_err(|e| K8sError::config_error(format!("创建命名空间失败: {}", e)))?;

        info!("命名空间 {} 创建成功", name);
        Ok(())
    }

    /// 删除命名空间
    pub async fn delete_namespace(&self, name: &str) -> K8sResult<()> {
        warn!("删除命名空间: {}", name);

        let namespaces: Api<Namespace> = Api::all(self.client.client().clone());
        namespaces.delete(name, &Default::default()).await
            .map_err(|e| K8sError::config_error(format!("删除命名空间失败: {}", e)))?;

        info!("命名空间 {} 删除成功", name);
        Ok(())
    }
}

/// 标签选择器
#[derive(Debug, Clone)]
pub struct LabelSelector {
    /// 匹配标签
    pub match_labels: HashMap<String, String>,
    /// 不匹配标签
    pub not_match_labels: HashMap<String, String>,
}

impl LabelSelector {
    /// 创建新的标签选择器
    pub fn new() -> Self {
        Self {
            match_labels: HashMap::new(),
            not_match_labels: HashMap::new(),
        }
    }

    /// 添加匹配标签
    pub fn match_label(mut self, key: &str, value: &str) -> Self {
        self.match_labels.insert(key.to_string(), value.to_string());
        self
    }

    /// 添加不匹配标签
    pub fn not_match_label(mut self, key: &str, value: &str) -> Self {
        self.not_match_labels.insert(key.to_string(), value.to_string());
        self
    }

    /// 检查标签是否匹配
    pub fn matches(&self, labels: &HashMap<String, String>) -> bool {
        // 检查必须匹配的标签
        for (key, value) in &self.match_labels {
            if labels.get(key) != Some(value) {
                return false;
            }
        }

        // 检查不能匹配的标签
        for (key, value) in &self.not_match_labels {
            if labels.get(key) == Some(value) {
                return false;
            }
        }

        true
    }

    /// 转换为 Kubernetes 标签选择器字符串
    pub fn to_selector_string(&self) -> String {
        let mut selectors = Vec::new();

        // 添加匹配条件
        for (key, value) in &self.match_labels {
            selectors.push(format!("{}={}", key, value));
        }

        // 添加不匹配条件
        for (key, value) in &self.not_match_labels {
            selectors.push(format!("{}!={}", key, value));
        }

        selectors.join(",")
    }
}

impl Default for LabelSelector {
    fn default() -> Self {
        Self::new()
    }
}

/// 资源配额信息
#[derive(Debug, Clone)]
pub struct ResourceQuota {
    /// CPU 限制
    pub cpu_limit: Option<String>,
    /// 内存限制
    pub memory_limit: Option<String>,
    /// 存储限制
    pub storage_limit: Option<String>,
    /// Pod 数量限制
    pub pod_limit: Option<i32>,
}

/// 健康检查工具
pub struct HealthCheckUtils;

impl HealthCheckUtils {
    /// 检查 Pod 是否健康
    pub fn is_pod_healthy(pod: &Pod) -> bool {
        if let Some(status) = &pod.status {
            // 检查 Pod 阶段
            if let Some(phase) = &status.phase {
                if phase != "Running" {
                    return false;
                }
            }

            // 检查容器状态
            if let Some(container_statuses) = &status.container_statuses {
                for container_status in container_statuses {
                    if !container_status.ready {
                        return false;
                    }
                }
            }

            return true;
        }
        false
    }

    /// 获取 Pod 重启次数
    pub fn get_pod_restart_count(pod: &Pod) -> i32 {
        if let Some(status) = &pod.status {
            if let Some(container_statuses) = &status.container_statuses {
                return container_statuses.iter()
                    .map(|cs| cs.restart_count)
                    .sum();
            }
        }
        0
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_validate_resource_name() {
        assert!(K8sUtils::validate_resource_name("valid-name").is_ok());
        assert!(K8sUtils::validate_resource_name("valid.name").is_ok());
        assert!(K8sUtils::validate_resource_name("123valid").is_ok());
        
        assert!(K8sUtils::validate_resource_name("").is_err());
        assert!(K8sUtils::validate_resource_name("-invalid").is_err());
        assert!(K8sUtils::validate_resource_name("invalid-").is_err());
        assert!(K8sUtils::validate_resource_name("Invalid-Name").is_err());
    }

    #[test]
    fn test_validate_label_key() {
        assert!(K8sUtils::validate_label_key("app").is_ok());
        assert!(K8sUtils::validate_label_key("app.kubernetes.io/name").is_ok());
        
        assert!(K8sUtils::validate_label_key("").is_err());
        assert!(K8sUtils::validate_label_key("-invalid").is_err());
    }

    #[test]
    fn test_validate_label_value() {
        assert!(K8sUtils::validate_label_value("valid-value").is_ok());
        assert!(K8sUtils::validate_label_value("").is_ok()); // 空值允许
        
        assert!(K8sUtils::validate_label_value("-invalid").is_err());
    }

    #[test]
    fn test_generate_standard_labels() {
        let labels = K8sUtils::generate_standard_labels("myapp", "1.0.0", "web");
        
        assert_eq!(labels.get("app.kubernetes.io/name"), Some(&"myapp".to_string()));
        assert_eq!(labels.get("app.kubernetes.io/version"), Some(&"1.0.0".to_string()));
        assert_eq!(labels.get("app.kubernetes.io/component"), Some(&"web".to_string()));
        assert_eq!(labels.get("app.kubernetes.io/managed-by"), Some(&"rustcloud".to_string()));
    }

    #[test]
    fn test_label_selector() {
        let selector = LabelSelector::new()
            .match_label("app", "web")
            .not_match_label("env", "test");

        let mut labels = HashMap::new();
        labels.insert("app".to_string(), "web".to_string());
        labels.insert("env".to_string(), "prod".to_string());

        assert!(selector.matches(&labels));

        labels.insert("env".to_string(), "test".to_string());
        assert!(!selector.matches(&labels));
    }

    #[test]
    fn test_selector_string() {
        let selector = LabelSelector::new()
            .match_label("app", "web")
            .not_match_label("env", "test");

        let selector_string = selector.to_selector_string();
        assert!(selector_string.contains("app=web"));
        assert!(selector_string.contains("env!=test"));
    }
}